package com.swdegao.iot.netty.server.qianbaotongplushandler;

import com.alibaba.fastjson.JSON;
import com.swdegao.iot.SwdegaoIotMgtServerApplication;
import com.swdegao.iot.netty.entity.*;
import com.swdegao.iot.netty.utils.ConvertUtils;
import com.swdegao.iot.netty.utils.RedisUtils;
import com.swdegao.iot.netty.utils.RocketMQUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import com.swdegao.iot.netty.server.qianbaotongplushandler.QianBaoTongProactiveModel.*;

import static com.swdegao.iot.netty.server.qianbaotongplushandler.QianBaoTongProactiveModel.Afn.REQUESTING;
import static com.swdegao.iot.netty.server.qianbaotongplushandler.QianBaoTongProactiveModel.Afn.TEST;

@Slf4j
public class QianBaoTongPlus_ParseMessgaeHandler extends SimpleChannelInboundHandler<Object> {

    @Autowired
    private RedisUtils redisUtils = SwdegaoIotMgtServerApplication.getBean(RedisUtils.class);
    @Autowired
    private RocketMQUtils rocketMQUtils = SwdegaoIotMgtServerApplication.getBean(RocketMQUtils.class);
    static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    //	private HandlerMessage hm = new HandlerMessage();
    @SuppressWarnings("unused")
    private String tempTime = null;// 用于比较心跳是否超时

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { // (4)
        ByteBuf in = (ByteBuf) msg;
        byte[] barray = new byte[in.readableBytes()];
        in.getBytes(0, barray);
        log.info("parse 获取到数据：" + Hex.encodeHexString(barray));


        QianBaoTongProactiveModel<Copy> qianBaoTongProactiveModel = QianBaoTongProactive.decodeCommonPart(barray);
        Fn fn = qianBaoTongProactiveModel.getFn();
        Afn afn = qianBaoTongProactiveModel.getAfn();
        Address address = qianBaoTongProactiveModel.getAddress();
        String concentratorAddr = address.getAddress();
        try {
            if (!QianBaoTongPlus_Const.hasChannelID(concentratorAddr)) {
                // 获取上线时设置的uuid
                String uuid = QianBaoTongPlus_Const.isChannel(ctx.channel());
                // 把UUID换成通讯地址
                QianBaoTongPlus_Const.ChangeClientId(uuid, concentratorAddr);
            }
            // 检查重复链接ID 不同实例 切换实例
            if (QianBaoTongPlus_Const.ischangeChannelID(concentratorAddr, ctx.channel())) {
                QianBaoTongPlus_Const.changeChannel(concentratorAddr, ctx.channel());
            }
            boolean sendToMqtt = true;
            String tag;
            // CON位置“1”，表示需要对该帧报文进行确认
            switch (qianBaoTongProactiveModel.getAfn()) {
                case TEST:
                    tag = TEST.name();
                    sendToMqtt = false;
                    byte[] command;
                    // 登录
                    Fn loginFn = new Fn(0, 1);
                    // 退出登录
                    Fn logoutFn = new Fn(0, 2);
                    // 心跳
                    Fn heartbeatFn = new Fn(0, 3);
                    if (loginFn.equals(fn) || logoutFn.equals(fn) || heartbeatFn.equals(fn)) {
                        command = QianBaoTongProactive.encodeResponseConfirm(address, afn, fn, true);
                    } else {
                        break;
                    }
                    log.info("回复报文：{}，解析qianBaoTongProactiveModel：{}", Hex.encodeHexString(command, false), qianBaoTongProactiveModel);

                    ctx.writeAndFlush(Unpooled.wrappedBuffer(command));
                    break;
                case REQUESTING:
                    tag = REQUESTING.name();
                    Fn meterDataFn = new Fn(0, 57);
                    if (meterDataFn.equals(fn)) {
                        Copy copy = QianBaoTongProactive.decodeCopyData(qianBaoTongProactiveModel.getDataUnitRaw());
                        qianBaoTongProactiveModel.setDataUnit(copy);
                        log.info("自动上报数据：{}", qianBaoTongProactiveModel);
                    }
                    break;
                default:
                    tag = qianBaoTongProactiveModel.getAfn().name();
                    break;
            }

            if (StringUtils.isNotBlank(concentratorAddr) && sendToMqtt) {
                CallBackData callBackData = new CallBackData();
                callBackData.setImei(concentratorAddr);
                callBackData.setCreatetime(System.currentTimeMillis());
                callBackData.setUpData(Hex.encodeHexString(barray));
                callBackData.setTopic(Parameter.QianBaoTong_RocektMq);
                callBackData.setTag(tag);
                rocketMQUtils.sendMessage(concentratorAddr, callBackData.getTopic(), callBackData.getTag(), rocketMQUtils.getCallBackBean(callBackData));

                if (!redisUtils.hmhave(Parameter.imei_info, concentratorAddr)) {
                    ImeiInfo imeiInfo = new ImeiInfo();
                    imeiInfo.setOnlineLastTime(System.currentTimeMillis());
                    imeiInfo.setOnlineStatus("1");
                    imeiInfo.setcType(Parameter.communication_tcp);
                    imeiInfo.setImei(concentratorAddr);
                    imeiInfo.setOutTime(Parameter.outtime_hear);
                    imeiInfo.setHeartbeat_registered_num(0);
                    imeiInfo.setHeartbeat_delay_num(0);
                    imeiInfo.setHeartbeat_cycle(Parameter.heartbeat_cycle);
                    redisUtils.hmSet(Parameter.imei_info, concentratorAddr, JSON.toJSONString(imeiInfo));
                }
            }
        } catch (Exception e) {
            log.error("千宝通设备 {}", concentratorAddr, e);
        }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
        QianBaoTongPlus_Const.add(String.valueOf(UUID.randomUUID()), ctx.channel());
        channels.add(ctx.channel());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
//		inactiveAction(ctx);

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (7)
        // 当出现异常就关闭连接
        cause.printStackTrace();
//		ctx.close();
    }

    private static void hexPlusOne(String hexString) throws DecoderException {

//		// 将十六进制字符串转换为整数
//		int decimalValue = Integer.parseInt(hexString, 16);
//
//		// 加1
//		int incrementedValue = decimalValue + 1;
//
//		// 将结果转换回十六进制字符串，并去掉前缀 "0x"
//		String incrementedHexString = Integer.toHexString(incrementedValue).toUpperCase();
//
//		// 打印结果
//		System.out.println("Original Hex: " + hexString);
//		System.out.println("Incremented Hex: " + incrementedHexString);
//		byte[] t = Hex.decodeHex(incrementedHexString);
//		return incrementedHexString.getBytes()[0];//控制码
        // 集中器回复
        byte pageByte = (byte) 1;
        // 将十六进制字符串转换为整数
        int decimalValue = Integer.parseInt(Integer.toHexString(pageByte), 16);
        // 加1
        int incrementedValue = decimalValue + 1;
        System.out.println((byte) incrementedValue);
    }


    public static void main(String arg[]) throws DecoderException {
        hexPlusOne("256");
    }

    /**
     * 将BCD码字节数组转换为字符串
     *
     * @param bcdBytes BCD码字节数组
     * @return 对应的十进制数字字符串
     */
    public static String bcdToString(byte[] bcdBytes) {
        StringBuilder result = new StringBuilder();

        // 遍历BCD码字节数组
        for (byte b : bcdBytes) {
            // 提取高四位表示的十进制数字
            int highNibble = (b & 0xF0) >> 4;
            // 提取低四位表示的十进制数字
            int lowNibble = b & 0x0F;

            // 将两个十进制数字添加到结果字符串中
            result.append(highNibble).append(lowNibble);
        }

        return result.toString();
    }

    /**
     * 上线操作
     *
     * @param imei
     * @param
     */
    private void onoffLineAction(String imei, String type, int status) {
        OnOffData onOff = new OnOffData();
        onOff.setImei(imei);
        onOff.setCreatetime(System.currentTimeMillis());
        onOff.setAction(type);
        redisUtils.lPush(imei + Parameter.on_off_info, JSON.toJSONString(onOff));// 存储所有updata数据
    }

    /**
     * 上线下线操作
     *
     * @param imei
     * @param
     */
    @SuppressWarnings("unused")
    private void onoffLineForCenter(String imei, int status) {
        Terminals terminal = new Terminals();
        terminal.setImei(imei);
        terminal.setOnlinestatus(status);
        // ts.updateTerminalOnlineStatus(terminal);
    }

    /**
     * 下线完整操作
     */
    private void inactiveAction(ChannelHandlerContext ctx) {
        String channelId = QianBaoTongPlus_Const.getChannelIds(ctx.channel());
        if (!"".equals(channelId) && !channelId.contains("_")) {
            onoffLineAction(channelId, Parameter.offline_des, 0);// 记录下线
            onoffLineForCenter(channelId, 0);
            // 清掉redis中关于心跳记录
            ImeiInfo imeiInfo = JSON.parseObject(redisUtils.hmGet(Parameter.imei_info, channelId).toString(), ImeiInfo.class);
            imeiInfo.setHeartbeat_delay_num(0);
            imeiInfo.setHeartbeat_registered_num(0);
            redisUtils.hmSet(Parameter.imei_info, channelId, JSON.toJSONString(imeiInfo));
        }
        QianBaoTongPlus_Const.remove(ctx.channel());
        channels.remove(ctx.channel());
    }

    public String getTimeNow() {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return df.format(new Date());
    }

    /**
     * 获取超时时间
     *
     * @param timeNow
     */
    public String getTimeOut(String timeNow) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar cal = new GregorianCalendar();

        try {
            cal.setTime(df.parse(timeNow));
            cal.add(Calendar.SECOND, Parameter.outtime_hear);

        } catch (ParseException e) {
            e.printStackTrace();
        }
        return df.format(cal.getTime());
    }

    /**
     * 比较超时时间，是否超时
     */
    public int CompareOutTime(String timeNow, String timeAfter, SimpleDateFormat timestampFormat) {
        if (timeNow.equals(timeAfter)) // same
            return 1;
        try {
            Date timesN = timestampFormat.parse(timeNow);
            Date timesA = timestampFormat.parse(timeAfter);
            if (timesA.after(timesN)) // time 1 is newer
                return 1;
            else return -1;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 1;
    }

    /**
     * @param
     * @param
     * @return
     */
    public ByteBuf ToDeviceClockMsg() {
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
        String date = df.format(new Date());
        byte[] temp2_ = ConvertUtils.getDateFromStrDX(date, 7);
        byte[] msg = new byte[8 + temp2_.length];
        msg[0] = (byte) 0xaa;
        msg[1] = 0x55;
        msg[2] = 0x07;
        msg[3] = 0x00;
        msg[4] = 0x16;
        msg[5] = 0x00;
        msg[6] = 0x00;

        System.arraycopy(temp2_, 0, msg, 7, 7);
        msg[msg.length - 1] = ConvertUtils.getTotalForByte(msg);

        return Unpooled.wrappedBuffer(msg);
    }

    /**
     * 四联协议统一回复
     *
     * @return
     */
    public ByteBuf ToDeviceallMsg(ByteBuf buf) {
        byte[] b = ByteBufUtil.getBytes(buf);
        byte[] temp = new byte[5];
        System.arraycopy(b, 7, temp, 0, temp.length);
        byte[] msg = new byte[17];
        msg[0] = (byte) 0x68;
        msg[1] = 0x27;
        msg[2] = 0x00;
        msg[3] = 0x27;
        msg[4] = 0x00;
        msg[5] = 0x68;
        msg[6] = 0x0A;
        System.arraycopy(temp, 0, msg, 7, temp.length);
        msg[12] = 0x00;
        msg[13] = 0x60;
        msg[14] = 0x01;
        temp = new byte[msg.length - 8];
        System.arraycopy(msg, 6, temp, 0, temp.length);
        msg[15] = ConvertUtils.getTotalForByte(temp);
        msg[16] = 0x16;
        return Unpooled.wrappedBuffer(msg);
    }


    public ByteBuf GetSuccessSignal(String imei, byte type, boolean suc) {
        byte[] msg = new byte[23];
        msg[0] = (byte) 0x80;
        msg[1] = 0x23;
        msg[2] = 0;
        msg[3] = type;
        byte[] temp = imei.getBytes();
        System.arraycopy(temp, 0, msg, 4, 15);// 类型、imei
        msg[19] = (byte) (suc ? 0x73 : 0x74);// 应答状态
        msg[20] = ConvertUtils.getTotalForByte(msg);// 校验和
        msg[21] = 0x0d;
        msg[22] = 0x0a;
        return Unpooled.wrappedBuffer(msg);
    }

    /**
     * 预置命令
     *
     * @param imei
     * @param presetCommand
     * @return
     * @throws DecoderException
     */
    public ByteBuf GetPresetCommand(String imei, PresetCommand presetCommand) throws DecoderException {
        byte[] downData = Hex.decodeHex(presetCommand.getDownData());
        int msg_length = 22 + downData.length;
        int msg_length_h = msg_length / 100;
        int msg_length_l = msg_length - (msg_length / 100) * msg_length_h;
        byte[] msg = new byte[msg_length];
        msg[0] = (byte) 0x80;
        msg[1] = (byte) Integer.parseInt(msg_length_l + "", 16);
        msg[2] = (byte) Integer.parseInt(msg_length_h + "", 16);
        msg[3] = (byte) 0x86;
        byte[] temp = imei.getBytes();
        System.arraycopy(temp, 0, msg, 4, 15);// 类型、imei
        System.arraycopy(downData, 0, msg, 19, downData.length);// 类型、imei
        msg[msg_length - 3] = ConvertUtils.getTotalForByte(msg);// 校验和
        msg[msg_length - 2] = 0x0d;
        msg[msg_length - 1] = 0x0a;
        return Unpooled.wrappedBuffer(msg);
    }

}
